//
// Class to show md5 meshes from Doom III
//
// Author: Alex V. Boreskoff <alexboreskoff@mtu-net.ru> <steps3d@narod.ru>
//

#ifndef	__MD5_MODEL__
#define	__MD5_MODEL__

struct	md5Vertex								// mesh vertex
{
	Vector2D	tex;
	int			weightIndex;
	int			weightCount;
};

struct	md5Triangle
{
	int	index [3];
};

struct	md5Weight
{
	int			jointIndex;					// for whuch bone this weight is for
	float		weight;						// looks like a weight of this pos
	Vector3D	pos;
};

class	md5HierarchyItem
{
public:
	std::string	name;
	int		parent;
	int		flags;
	int		startIndex;
};

class	BaseFrameJoint
{
public:
	Vector3D	pos;
	Quaternion	orient;
};

class	md5Joint
{
public:
	std::string		name;
	int			parentIndex;
	md5Joint     * parent;
	Vector3D	pos;
	Quaternion	orient;

	Vector3D	transform ( const Vector3D& v ) const
	{
		return orient.rotate ( v ) + pos;
	}

	Vector3D	invTransform ( const Vector3D& v ) const
	{
		Quaternion	c ( orient );

		return c.conj ().rotate ( v ) - pos;
	}
};

class	Md5Mesh
{
public:
	std::string		shader;
	int			numVertices;
	md5Vertex    * vertices;
	int			numTris;
	md5Triangle  * tris;
	int			numWeights;
	md5Weight    * weights;
	Vector3D  * points;
	int		 	maxJpv;						// maximum joints (weights) per vertex
	unsigned int diffuseMap;
	unsigned int specularMap;
	unsigned int bumpMap;

public:
	Md5Mesh  ();
	~Md5Mesh ();

	void	setNumVertices ( int n );
	void	setNumTris     ( int n );
	void	setNumWeights  ( int n );

	void	setShader      ( const std::string& sh )
	{
		shader = sh;
	}

	void	setVertex ( int index, const Vector2D& tex, int blendIndex, int blendCount );
	void	setTri    ( int index, int i1, int i2, int i3 );
	void	setWeight ( int index, int bone, float bias, const Vector3D& weight );

	void	calcPoints ( md5Joint * joints );			// compute real points from bones data
	void	draw       ();							// draw itself
	bool	loadShader ( const std::string& path );		// load textures

//	friend class Model;
};

class	Md5Model
{
public:
	int		    numJoints;
	md5Joint     * joints;
	int		    numMeshes;
	Md5Mesh   * meshes;

public:
	Md5Model  ();
	~Md5Model ();

	int		getNumJoints () const
	{
		return numJoints;
	}

	md5Joint * getJoints () const
	{
		return joints;
	}

	void	setNumJoints ( int n );
	void	setNumMeshes ( int n );

	bool	load          ( const std::string& modelName );
	bool	loadJoints    ( Data * data );

	void	compute      ( md5Joint * joints );
	void	Draw         ();
	void	drawSkeleton ( bool absoluteJoints, md5Joint * joints );

protected:
	void	drawJoint    ( md5Joint * joints, int i1, int i2, bool absoluteJoints );
};

bool	getLine   ( Data * data, std::string& str );
void	splitPath ( const std::string& fullName,std::string& fileName, std::string& ext );

#endif
